package com.sonic.db.utils;

import java.net.URL;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import com.sonic.log.ejb.impl.MQLogger;

public class MQHibernateUtil {
	private static MQLogger logger = new MQLogger(MQHibernateUtil.class, "MQ-DB-UTIL");
	
	private static SessionFactory sessionFactory = null;	
	private static final ThreadLocal<Session> currentSession = new ThreadLocal<Session>();	
	private static final Owner trueOwner = new Owner(true);	
	private static final Owner fakeOwner = new Owner(false);
	
	public MQHibernateUtil() {}
	
	/**
	 * Get the hibernate session and set it on the thread local. Returns trueOwner if it actually opens a session
	 */
	public static Object createSession() throws Exception {
		final String methodName = "createSession()";
		final Session session = (Session) currentSession.get();
		if(session != null)
			logger.debug(methodName, session.toString());
		if (session == null) {
			logger.debug(methodName, "No Session Found - Create and give the identity");
			MQHibernateUtil.currentSession.set(getSessionFactory().openSession());
			return trueOwner;
		}
		logger.debug(methodName, "Session Found - Give a Fake identity");
		return fakeOwner;
	}
	
	/**
	 * The method for closing a session. The close and flush will be executed only if the session is actually created by this owner.
	 */
	public static void closeSession(Object ownership) throws Exception {
		final String methodName = "closeSession()";
		if (((Owner) ownership).identity) {
			logger.debug(methodName, "Identity is accepted. Now closing the session");
			Session session = (Session) currentSession.get();
			session.flush();
			session.close();
			MQHibernateUtil.currentSession.set(null);
		} else {
			logger.debug(methodName, "Identity is rejected. Ignoring the request");
		}
	}
	
	/**
	 * Returns the current session.
	 */
	public static Session getSession() throws HibernateException {
		return (Session) currentSession.get();
	}
	
	/**
	 * Creating a session factory , if not already loaded.
	 */
	private static SessionFactory getSessionFactory() throws HibernateException {
		try {
			if (sessionFactory == null) {
				Configuration configuration = new Configuration();
				URL url = MQHibernateUtil.class.getClassLoader().getResource("cfg/hibernate.cfg.xml");
				configuration.configure(url);
				sessionFactory = configuration.buildSessionFactory();
			}
			return sessionFactory;
		} catch (Exception e) {
			throw new HibernateException("Error getting Factory");
		}
	}
	
	/**
	 * Internal class , for handling the identity.
	 */
	private static class Owner {
		public Owner(boolean identity) {
			this.identity = identity;
		}
		
		boolean identity = false;
	}	
}